package com.jilefojing.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jilefojing.beans.exception.UserTokenException;
import com.jilefojing.beans.pojos.enhanced.EnhancedUserSession;
import com.jilefojing.context.beans.vo.RememberMe;
import com.jilefojing.context.beans.vo.UserToken;

/**
 * @author jgshun
 * @date 2016-4-13 下午3:27:07
 * @version 1.0
 */
public class UserTokenUtil {
	public static final int USER_TOKEN_COOKIE_LIFE_SECONDS = 2592000;

	private final static Logger _LOGGER = LoggerFactory.getLogger(UserTokenUtil.class);

	public static UserToken getUserTokenFromCookie(HttpServletRequest request) {
		return CookieUtil.getUserToken(request);
	}

	public static void writeUserTokenToCookie(UserToken userToken, HttpServletResponse response) {
		CookieUtil.writeUserToken(userToken, response);
	}

	public static void clearUserTokenFromCookie(HttpServletRequest request, HttpServletResponse response) {
		CookieUtil.clearUserToken(request, response);
	}

	public static void checkUserToken(UserToken userToken, EnhancedUserSession enhancedUserSession) throws UserTokenException {
		if (!Detect.notEmpty(userToken.getSign()) || !Detect.notEmpty(userToken.getToken()) || !Detect.notEmpty(userToken.getUid()) || userToken.getTime() == null) {
			throw new UserTokenException("[USERTOKEN属性不能有空值]");
		}

		if (enhancedUserSession == null && userToken.getRm() != null && userToken.getRm().isRm()) {
			enhancedUserSession = userToken.getRm().getSer();
		}

		if (enhancedUserSession == null) {
			throw new UserTokenException("[USERSESSION不能为空]");
		}

		String sign = generateSign(userToken, enhancedUserSession.getEnhancedUser().getId());

		if (!userToken.getSign().equals(sign) || !userToken.getSign().equals(enhancedUserSession.getSign())) {
			throw new UserTokenException("[SIGN有误]");
		}
		if (!userToken.getToken().equals(enhancedUserSession.getToken())) {
			throw new UserTokenException("[TOKEN有误]");
		}

		Date validDate = new Date();
		long validTime = enhancedUserSession.getTime().getTime() + (USER_TOKEN_COOKIE_LIFE_SECONDS * 1000L);
		validDate.setTime(validTime);

		if (validDate.before(new Date())) {
			throw new UserTokenException("[USERTOKEN已过期]");
		}
	}

	public static UserToken generateUserToken(boolean isRM, EnhancedUserSession enhancedUserSession) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
		UserToken userToken = new UserToken();
		userToken.setTime(enhancedUserSession.getTime());

		StringBuilder uid = new StringBuilder();
		DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		uid.append(df.format(enhancedUserSession.getTime().getTime())).append("~");
		Random rad = new Random();
		uid.append(rad.nextInt(1000000000));

		enhancedUserSession.setUid(uid.toString());

		userToken.setUid(uid.toString());
		userToken.setToken(generateToken(enhancedUserSession));
		userToken.setSign(generateSign(userToken, enhancedUserSession.getEnhancedUser().getId()));

		RememberMe rememberMe = null;
		if (isRM) {
			rememberMe = generateRememberMe(enhancedUserSession);
		} else {
			rememberMe = new RememberMe();
			rememberMe.setSer(new EnhancedUserSession());
			rememberMe.setRm(isRM);
		}

		userToken.setRm(rememberMe);

		return userToken;
	}

	public static RememberMe generateRememberMe(EnhancedUserSession enhancedUserSession) throws InvalidKeyException, UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
			IllegalBlockSizeException, BadPaddingException {
		RememberMe rememberMe = new RememberMe();
		rememberMe.setRm(true);

		String _pwd = enhancedUserSession.getEnhancedUser().getPassword();
		if (Detect.notEmpty(_pwd)) {
			enhancedUserSession.getEnhancedUser().setPassword(new String(AESCoder.encrypt(_pwd.getBytes("UTF8"), Base64.decodeBase64(enhancedUserSession.getSecretKey().getBytes("UTF8"))), "UTF8"));
		}
		rememberMe.setSer(enhancedUserSession);
		return rememberMe;
	}

	private static String generateSign(UserToken userToken, long userId) {
		StringBuilder signBud = new StringBuilder();
		signBud.append("time=").append(userToken.getTime().getTime()).append("_token=").append(userToken.getToken()).append("_uid=").append(userToken.getUid()).append("_userId=").append(userId);
		return MD5Util.getMD5Str(signBud.toString());
	}

	private static String generateToken(EnhancedUserSession enhancedUserSession) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException,
			BadPaddingException, UnsupportedEncodingException {
		StringBuilder tokenBud = new StringBuilder();
		tokenBud.append(enhancedUserSession.getUid()).append("_").append(enhancedUserSession.getPlatform().getValue()).append("_").append(enhancedUserSession.getTime().getTime());

		String token = new String(Base64.encodeBase64(AESCoder.encrypt(tokenBud.toString().getBytes("UTF8"), Base64.decodeBase64(enhancedUserSession.getSecretKey().getBytes("UTF8")))), "UTF8");

		return token;
	}

}
